# Auto build and file monitoring script for Wake-on-LAN toolkit

# Function to set up Visual Studio environment variables
function SetupVisualStudioEnvironment {
    # Try to find Visual Studio installation
    $vs2022Community = "C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Auxiliary\Build\vcvars32.bat"
    $vs2022Professional = "C:\Program Files\Microsoft Visual Studio\2022\Professional\VC\Auxiliary\Build\vcvars32.bat"
    $vs2022Enterprise = "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvars32.bat"
    $vs2019Community = "C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Auxiliary\Build\vcvars32.bat"
    $vs2019Professional = "C:\Program Files (x86)\Microsoft Visual Studio\2019\Professional\VC\Auxiliary\Build\vcvars32.bat"
    $vs2019Enterprise = "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Auxiliary\Build\vcvars32.bat"
    
    # Add MSBuild path manually
    $msbuildPaths = @(
        "C:\Program Files\Microsoft Visual Studio\2022\Community\MSBuild\Current\Bin",
        "C:\Program Files\Microsoft Visual Studio\2022\Professional\MSBuild\Current\Bin",
        "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\MSBuild\Current\Bin",
        "C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\MSBuild\Current\Bin",
        "C:\Program Files (x86)\Microsoft Visual Studio\2019\Professional\MSBuild\Current\Bin",
        "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\MSBuild\Current\Bin"
    )

    $vsPath = $null
    if (Test-Path $vs2022Community) { $vsPath = $vs2022Community }
    elseif (Test-Path $vs2022Professional) { $vsPath = $vs2022Professional }
    elseif (Test-Path $vs2022Enterprise) { $vsPath = $vs2022Enterprise }
    elseif (Test-Path $vs2019Community) { $vsPath = $vs2019Community }
    elseif (Test-Path $vs2019Professional) { $vsPath = $vs2019Professional }
    elseif (Test-Path $vs2019Enterprise) { $vsPath = $vs2019Enterprise }

    if ($vsPath) {
        Write-Host "Setting up Visual Studio environment..."
        
        try {
            # 静默执行vcvars32.bat，重定向输出以避免显示错误信息
            & cmd.exe /c ""$vsPath" >nul 2>&1"
            
            # 手动添加MSBuild路径到环境变量
            foreach ($path in $msbuildPaths) {
                if (Test-Path $path) {
                    $env:Path = "$path;$env:Path"
                    Write-Host "Added MSBuild path: $path" -ForegroundColor Green
                    break
                }
            }
            
            # 验证编译器环境是否可用
            if (Get-Command "cl.exe" -ErrorAction SilentlyContinue) {
                Write-Host "Visual Studio environment setup completed successfully." -ForegroundColor Green
            } else {
                Write-Host "Visual Studio environment setup completed." -ForegroundColor Yellow
                Write-Host "Note: Some environment warnings may have occurred, but the build should still work." -ForegroundColor Yellow
            }
            
            return $true
        } catch {
            Write-Host "Visual Studio environment setup encountered an issue, but continuing anyway." -ForegroundColor Yellow
            # 即使设置环境失败，我们也继续尝试构建，因为msbuild可能仍然可用
            return $true
        }
    } else {
        Write-Host "Visual Studio environment variables not found." -ForegroundColor Yellow
        Write-Host "Trying to manually add MSBuild path..." -ForegroundColor Yellow
        
        # 尝试手动添加MSBuild路径
        $msbuildFound = $false
        foreach ($path in $msbuildPaths) {
            if (Test-Path $path) {
                $env:Path = "$path;$env:Path"
                Write-Host "Added MSBuild path: $path" -ForegroundColor Green
                $msbuildFound = $true
                break
            }
        }
        
        # 检查msbuild是否可用
        if (-not $msbuildFound -and -not (Get-Command "msbuild" -ErrorAction SilentlyContinue)) {
            Write-Host "Error: msbuild not found!" -ForegroundColor Red
            Write-Host "Please install Visual Studio or add msbuild to your system path." -ForegroundColor Red
            return $false
        }
        return $true
    }
}

# Function to build the projects
function BuildProject {
    param (
        [string]$projectFile,
        [string]$projectName
    )

    if (-not (Test-Path $projectFile)) {
        Write-Host "$projectName project file not found!" -ForegroundColor Red
        return $false
    }

    Write-Host "Building $projectName project..."
    # 使用基本的优化参数，确保两个项目都能成功构建
    $buildResult = msbuild $projectFile "/p:Configuration=Release" "/p:Platform=Win32" "/t:Rebuild" "/nologo"
    
    if ($LASTEXITCODE -ne 0) {
        Write-Host "$projectName build failed!" -ForegroundColor Red
        return $false
    } else {
        Write-Host "$projectName build successful!" -ForegroundColor Green
        return $true
    }
}

# Function to monitor file changes
function MonitorFileChanges {
    param (
        [string[]]$directories,
        [string[]]$extensions
    )

    # Initialize file hashes
    $fileHashes = @{}
    $allFiles = @()

    # Folders to ignore
    $ignoreFolders = @(".vs", "Release", "Debug", "obj", "bin")

    # Function to update file hashes
    function UpdateFileHashes {
        $newFiles = @()
        foreach ($dir in $directories) {
            if (Test-Path $dir) {
                $newFiles += Get-ChildItem -Path $dir -Recurse -File | 
                              Where-Object { 
                                  $file = $_
                                  $extensions -contains $file.Extension.ToLower() -and 
                                  -not ($ignoreFolders | Where-Object { $file.FullName -like "*$_\*" })
                              }
            }
        }
        
        return $newFiles
    }

    # Initial file scan
    $allFiles = UpdateFileHashes
    foreach ($file in $allFiles) {
        $hash = Get-FileHash -Path $file.FullName -Algorithm MD5 -ErrorAction SilentlyContinue
        if ($hash) {
            $fileHashes[$file.FullName] = $hash.Hash
        }
    }

    Write-Host "File monitoring started. Watching $($allFiles.Count) files." -ForegroundColor Yellow
    Write-Host "Press Ctrl+C to stop monitoring."

    # Main monitoring loop
    try {
        while ($true) {
            Start-Sleep -Seconds 1
            
            $newFiles = UpdateFileHashes
            $changed = $false
            $changedDirs = @()
            
            # Check for new files
            $diff = Compare-Object -ReferenceObject $allFiles -DifferenceObject $newFiles -Property FullName -PassThru
            $addedFiles = $diff | Where-Object { $_.SideIndicator -eq '=>' }
            
            if ($addedFiles.Count -gt 0) {
                Write-Host "$($addedFiles.Count) new file(s) detected." -ForegroundColor Yellow
                foreach ($file in $addedFiles) {
                    $hash = Get-FileHash -Path $file.FullName -Algorithm MD5 -ErrorAction SilentlyContinue
                    if ($hash) {
                        $fileHashes[$file.FullName] = $hash.Hash
                        Write-Host "Added: $($file.FullName)" -ForegroundColor Green
                        # Determine which directory the file belongs to
                        foreach ($dir in $directories) {
                            if ($file.FullName -like "*$dir*") {
                                $changedDirs += $dir
                                break
                            }
                        }
                    }
                }
                $changed = $true
            }
            
            # Check for modified files
            foreach ($file in $newFiles) {
                if ($fileHashes.ContainsKey($file.FullName)) {
                    $currentHash = Get-FileHash -Path $file.FullName -Algorithm MD5 -ErrorAction SilentlyContinue
                    if ($currentHash -and $currentHash.Hash -ne $fileHashes[$file.FullName]) {
                        $fileHashes[$file.FullName] = $currentHash.Hash
                        Write-Host "Modified: $($file.FullName)" -ForegroundColor Yellow
                        $changed = $true
                        # Determine which directory the file belongs to
                        foreach ($dir in $directories) {
                            if ($file.FullName -like "*$dir*") {
                                $changedDirs += $dir
                                break
                            }
                        }
                    }
                }
            }
            
            # Check for deleted files
            $deletedFiles = $diff | Where-Object { $_.SideIndicator -eq '<=' }
            if ($deletedFiles.Count -gt 0) {
                Write-Host "$($deletedFiles.Count) file(s) deleted." -ForegroundColor Red
                foreach ($file in $deletedFiles) {
                    if ($fileHashes.ContainsKey($file.FullName)) {
                        $fileHashes.Remove($file.FullName)
                        Write-Host "Deleted: $($file.FullName)" -ForegroundColor Red
                        $changed = $true
                        # Determine which directory the file belongs to
                        foreach ($dir in $directories) {
                            if ($file.FullName -like "*$dir*") {
                                $changedDirs += $dir
                                break
                            }
                        }
                    }
                }
            }
            
            # Rebuild if changes detected
            if ($changed) {
                Write-Host "Changes detected, rebuilding projects..." -ForegroundColor Magenta
                $allFiles = $newFiles
                
                # Remove duplicate directories
                $changedDirs = $changedDirs | Select-Object -Unique
                
                # Determine which projects to rebuild based on changed directories
                $rebuildWolcmd = $false
                $rebuildWollisten = $false
                
                if ($changedDirs -contains "resources") {
                    # If resources directory changed, rebuild all projects
                    $rebuildWolcmd = $true
                    $rebuildWollisten = $true
                    Write-Host "Resources directory changed, rebuilding all projects." -ForegroundColor Blue
                } else {
                    # Otherwise, rebuild only the projects corresponding to the changed directories
                    if ($changedDirs -contains "wolcmd") {
                        $rebuildWolcmd = $true
                        Write-Host "WOLCmd directory changed, rebuilding wolcmd project." -ForegroundColor Blue
                    }
                    if ($changedDirs -contains "wollisten") {
                        $rebuildWollisten = $true
                        Write-Host "WOLListen directory changed, rebuilding wollisten project." -ForegroundColor Blue
                    }
                }
                
                # Rebuild the necessary projects
                if ($rebuildWolcmd) {
                    $wolcmdResult = BuildProject -projectFile "wolcmd\wolcmd.vcxproj" -projectName "wolcmd"
                }
                if ($rebuildWollisten) {
                    $wollistenResult = BuildProject -projectFile "wollisten\wollisten.vcxproj" -projectName "wollisten"
                }
                
                Write-Host "Rebuild complete. Resuming file monitoring." -ForegroundColor Magenta
            }
        }
    } catch [System.Management.Automation.KeyboardInterrupt] {
        Write-Host "Monitoring stopped." -ForegroundColor Green
    }
}

# Main function
function Main {
    # Setup Visual Studio environment
    if (-not (SetupVisualStudioEnvironment)) {
        return 1
    }

    Write-Host "Auto Build and Monitor Tool for Wake-on-LAN Kit" -ForegroundColor Magenta
    Write-Host "=============================================" -ForegroundColor Magenta

    # Build projects initially
    Write-Host "Building projects initially..."
    $wolcmdResult = BuildProject -projectFile "wolcmd\wolcmd.vcxproj" -projectName "wolcmd"
    $wollistenResult = BuildProject -projectFile "wollisten\wollisten.vcxproj" -projectName "wollisten"

    if (-not $wolcmdResult -and -not $wollistenResult) {
        Write-Host "Initial build failed!" -ForegroundColor Red
        return 1
    }

    # Start monitoring files
    $directoriesToMonitor = @("wolcmd", "wollisten", "resources")
    $fileExtensionsToMonitor = @(".cpp", ".h", ".rc", ".ico", ".vcxproj", ".sln")
    MonitorFileChanges -directories $directoriesToMonitor -extensions $fileExtensionsToMonitor

    return 0
}

# Run the main function
Main